home *** CD-ROM | disk | FTP | other *** search
Text File | 2000-09-28 | 19.9 KB | 670 lines | [TEXT/CWIE] |
- /*
- File: GXToPostScript.cp
-
- Contains: QuickDraw GX to PostScript conversion code.
- This file implements the Class for controling the GXToPostScript system.
-
- Version: Technology: Quickdraw GX 1.1.x
-
- Copyright: © 1997 by Apple Computer, Inc., all rights reserved.
- */
-
- #include "GXExceptions.h"
- #include "GXtoPostScript.h"
- #include "GXExceptions.h"
- #include "PublicPostScriptIE.h"
- #include <GXFonts.h>
- #include "GXGraphicsPriv.h"
- #include "ProcessShape.h"
-
- gxShape CGXToPSBuildShapeDbaseTags(gxShape theShape);
- Boolean CGXtoPostScriptDoesShapeHaveTMode(gxShape aShape);
-
- /****
- This method creates a font handler context from the
- font database.
- ****/
- void CGXtoPostScriptTranslator::CreateFontHandler(scalerStreamTypeFlag legalStreamTypes, TFHDownloadFlags flags)
- {
- TFontHandlerContext result = nil;
- OSErr status;
-
- /* Save the font handler settings */
- mLegalStreamTypes = legalStreamTypes;
- mFHDownloadFlags = flags;
-
- /* If the database isn't nil, create a font handler. */
- if (mDbase != nil) {
-
- // FInd out about the product.
- Str255 version, revision, product;
- status = this->mDevice->GetPSProduct(version, revision, product);
- if (status != noErr)
- throw status;
-
- // Now create a font handler context.
- status = FontHandlerInit(&mFontHandler, this->mDevice, mDbase, legalStreamTypes, flags, version, revision, product);
- if (status != noErr) throw status;
-
- status = FontHandlerSetFontVM(mFontHandler, mVMAvailable - kGXtoPSProcSetVM);
- if (status != noErr) throw status;
-
- }//end if
-
- }//CGXtoPostScriptTranslator::CreateFontHandler
-
- /********************
-
- This is the constructor for the GX-PS
- Translator.
-
- It allocates the buffers and the PSIE context.
-
- psDevice: A pointer to a device object which handles the GX PostScript messages.
-
- imageData: This is the image data handle. This specifies the capabilities of the target postscript device.
-
- fontDbase: Nil for draw by draw font management, or a valid font database object.
-
- devMapping: This is a matrix that maps from 72dpi space to device space. This matrix will be used to make
- device resolution bitmaps for text and transfer modes.
-
- halftoneRecord: This specifies the default halftone for this job. If nil, the printers default will be used.
-
- *********************/
- CGXtoPostScriptTranslator::CGXtoPostScriptTranslator(CGXtoPostScriptDevice* psDevice, gxPostScriptImageDataRec *imageData,
- TFontDbase fontDbase, gxMapping *devMapping, gxFormatHalftoneInfo *halftoneRecord)
- {
- mTransformStack = nil;
- mTransformCount = 0;
- mStackAllocation = 0;
- mDbase = fontDbase;
- mFontHandler = nil;
- mVMAvailable = imageData->printerVM;
-
- OSErr status = noErr;
-
- mDevice = psDevice;
-
- /** Create a font handler context **/
- TFHDownloadFlags fhFlags = fhNoDownloadFlags;
-
- if (imageData->renderOptions & gxNeedsHexOption)
- fhFlags |= fhDownloadAscii;
-
- if (imageData->languageLevel >= 2) // Assume for level-2 we can do composite fonts.
- fhFlags |= fhUseTypeZeroFonts;
-
- this->CreateFontHandler(imageData->fontType, fhFlags);
-
- /** Create an Imaging Engine context **/
- status = EnterPostScriptIE(&mPSIEContext, mDevice, imageData, mFontHandler, nil );
- if (status != noErr) throw status;
-
- /* Grab this information for potential transfer mode dealings */
- if (devMapping != nil)
- CopyToMapping(&mDeviceMapping, devMapping);
-
- if (imageData != nil) {
- mDevColorSpace = imageData->devCSpace;
- mDevProfile = imageData->devCProfile;
- }//end if
-
-
-
- }//CGXtoPostScriptTranslator
-
- /***********
- The destructor cleans up.
- ************/
- CGXtoPostScriptTranslator::~CGXtoPostScriptTranslator()
- {
- if (mTransformStack != nil)
- delete [] mTransformStack;
-
- OSErr status = ExitPostScriptIE(mPSIEContext);
-
- if (mFontHandler != nil) {
- OSErr status2 = FontHandlerShutdown(mFontHandler);
- if (status == noErr) status = status2;
- }//end if
-
- if (status != noErr) throw status;
-
- }//~CGXtoPostScriptTranslator
-
- /*********
- This method is invoked at the beginning of each page to be rendered.
-
- imageData: Pointer to an image data record. Although one was passed to the constructor,
- We allow the device color profile to be changed on a page by page basis. That is the only
- field of the imageData that is used in this call.
-
- devMapping: Again, we allow this to be changed on a page by page basis.
- halftoneRecord: This, too on a page by page basis.
-
- *********/
- void CGXtoPostScriptTranslator::InitGraphics(gxPostScriptImageDataRec *imageData, gxMapping *devMapping, gxFormatHalftoneInfo *halftoneRecord)
- {
- /* Grab this information for potential transfer mode dealings */
- if (devMapping != nil)
- CopyToMapping(&mDeviceMapping, devMapping);
-
- if (imageData != nil) {
- mDevColorSpace = imageData->devCSpace;
- mDevProfile = imageData->devCProfile;
- }//end if
-
- /* Now initialize the graphics state of the imaging engine */
- OSErr status = PostScriptInitGraphics(mPSIEContext, imageData, devMapping, halftoneRecord);
- if (status != noErr)
- throw status;
-
- }//CGXtoPostScriptTranslator::InitGraphics
-
-
- /**********
- This method is called to translate a shape to PostScript.
- Typically this is called with a picture for the whole page,
- but this isn't a requirement.
- ***********/
- void CGXtoPostScriptTranslator::DrawShape(gxShape theShape, Boolean imageTransferModes)
- {
- Boolean pageByPageFonts = (mDbase == nil) ? true : false;
- OSErr status = noErr;
- gxShape shapeToDraw = theShape;
-
- /* Handle fonts if necessary */
- if (pageByPageFonts) {
-
- /* Build a font database for this shape. */
- status = FontDbaseInit(&mDbase, nil);
- nrequire(status, failed_dbaseInit);
- shapeToDraw = CGXToPSBuildShapeDbaseTags(theShape);
- status = FontDbaseAddPage(mDbase, shapeToDraw, false);
- nrequire(status, failed_addPage);
-
- /* Now create a font handler for this shape */
- try {
- this->CreateFontHandler(mLegalStreamTypes, mFHDownloadFlags);
- } catch (OSErr error) {
- status = error;
- }//end try-catch
- nrequire(status, failed_createFH);
-
- /* Now do the font handler doc-level fonts */
- status = mDevice->BufferData("%-- Font Handling: Treating each CGXtoPostScriptTranslator::DrawShape Seperately\r", 81, 0);
- nrequire(status, failed_buff1);
-
- status = FontHandlerDoDocumentHeader(mFontHandler);
- nrequire(status, failed_docHeader);
-
- PostScriptIEReplaceFontHandler(mPSIEContext, mFontHandler);
-
-
- }//end if
-
- /* Draw the shape */
- gxShape tModes = this->InternalDrawShape(shapeToDraw, imageTransferModes);
-
- /* Deal with the transfer modes if necessary */
- if (tModes != nil) {
- this->RenderTransferModes(theShape, tModes);
- GXDisposeShape(tModes);
- }//end if
-
-
- failed_docHeader:
- failed_buff1:
- failed_doSave:
- failed_createFH:
- failed_addPage:
-
- /* Deal with font stuff if necessary */
- if (pageByPageFonts) {
- status = FontHandlerShutdown(mFontHandler);
- OSErr saveStatus = FontDbaseShutdown(mDbase, nil);
- if (status == noErr) status = saveStatus;
- mDbase = nil;
- mFontHandler = nil;
-
- if (status == noErr)
- status = mDevice->BufferData("%-- End Font Handling: Treating each CGXtoPostScriptTranslator::DrawShape Seperately\r", 85, 0);
-
- }//end if
-
- if (shapeToDraw != theShape)
- GXDisposeShape(shapeToDraw);
-
- failed_dbaseInit:
- if (status != noErr) throw status;
-
- }//CGXtoPostScriptTranslator::DrawShape
-
-
- /**********
- This method is invoked after imaging a page.
- **********/
- void CGXtoPostScriptTranslator::RestoreGraphics(void)
- {
- OSErr status = PostScriptRestoreGraphics(mPSIEContext);
- if (status != noErr)
- throw status;
-
- }//CGXtoPostScriptTranslator::RestoreGraphics
-
-
- /*****************
-
- Download the required procsets for GX.
-
- ******************/
- void CGXtoPostScriptTranslator::DownloadProcSets()
- {
- OSErr status = PostScriptIEDownloadProcSets(mPSIEContext);
- if (status != noErr)
- throw status;
-
- status = FontHandlerDownloadProcSetList(mDevice);
- if (status != noErr)
- throw status;
-
- }//CGXtoPostScriptTranslator::DownloadProcSets
-
-
-
- /***************** Methods for traversing pictures ******************/
-
- /****************
- The drawshape method.
- This is invoked for each shape to be drawn.
- If the input shape is a picture, it will be walked recursively using
- the transform stack methods.
-
- Function result: A shape is created and returned which contains all the shapes passed in that had transfer modes.
- or nil, if the input didn't have any transfer modes.
-
- ****************/
- gxShape CGXtoPostScriptTranslator::InternalDrawShape(gxShape theShape, Boolean imageTransferModes)
- {
- gxShape result = nil;
- gxShapeType theType = GXGetShapeType(theShape);
-
- if (theType != gxPictureType) {
-
- /* Draw the shape. If it had a transfer mode, return it as the result so it can be accumulated */
-
- if ( imageTransferModes && CGXtoPostScriptDoesShapeHaveTMode(theShape) )
- result = GXCloneShape(theShape);
-
- /*
- When we are doing transfer modes as an image, we may have to redraw the shape into an offscreen
- in the second pass. Since the imaging engine tends to be destructive to shapes if it thinks the shape is only used once,
- we clone the shape here to "trick" the imaging engine into making a copy of the shape before
- doing any destructive activities.
- */
- if ( imageTransferModes )
- GXCloneShape(theShape);
-
- OSErr status = PostScriptDrawShape(mPSIEContext, theShape, mTransformStack, mTransformCount);
-
- if ( imageTransferModes ) // clean up our clone if we made one above.
- GXDisposeShape(theShape);
-
- if (status != noErr)
- throw status;
-
-
- } else {
-
- /** Recursively draw each shape in the picture */
- this->PushTransform(GXGetShapeTransform(theShape));
-
- gxTransform oldTr, overTr;
- gxStyle oldSt, overSt;
- gxInk oldInk, overInk;
- gxShape child;
- long count = GXGetPictureParts(theShape, 1, gxSelectToEnd, nil, nil, nil, nil);
-
- // Create a picture to contain any of the shapes that had transfer modes.
- if (imageTransferModes) {
- result = GXNewShape(gxPictureType);
- GXSetShapeTransform(result, GXGetShapeTransform(theShape));
- }//end if
-
- for (long i = 1; i <= count; ++i) {
-
- GXGetPictureParts(theShape, i, 1, &child, &overSt, &overInk, &overTr);
-
- /* Apply the overrides to the child shape*/
- if (overSt) {
- oldSt = GXCloneStyle(GXGetShapeStyle(child)); // save a reference to the old style
- GXSetShapeStyle(child, overSt); // Apply the overriding style.
- }//end if
- if (overInk) {
- oldInk = GXCloneInk(GXGetShapeInk(child)); // save a reference to the old ink
- GXSetShapeInk(child, overInk); // Apply the overriding ink.
- }//end if
- if (overTr) {
- oldTr = GXCloneTransform(GXGetShapeTransform(child)); // save a reference to the old transorm
- GXSetShapeTransform(child, overTr); // Apply the overriding transform.
- }//end if
-
- // Call draw recursinvely on the child.
- gxShape drawnShape = this->InternalDrawShape(child, imageTransferModes);
-
- /* If the shape we drew had any transfer modes, then add it to the result */
- if (drawnShape != nil) {
- gxStyle *pStyle = (overSt != nil) ? &overSt : nil;
- gxTransform *pTransform = (overTr != nil) ? &overTr : nil;
- gxInk *pInk = (overInk != nil) ? &overInk : nil;
- GXSetPictureParts(result, 0, 0, 1, &drawnShape, pStyle, pInk, pTransform);
- GXDisposeShape(drawnShape); // picture owns it, we don't need it anymore.
- }//end if
-
-
- /* Restore the non-overriding style, ink and transform */
- if (overSt) {
- GXSetShapeStyle(child, oldSt);
- GXDisposeStyle(oldSt);
- }//end if
- if (overInk) {
- GXSetShapeInk(child, oldInk);
- GXDisposeInk(oldInk);
- }//end if
- if (overTr) {
- GXSetShapeTransform(child, oldTr);
- GXDisposeTransform(oldTr);
- }//end if
-
- }//end for
-
- // Return nil if we didn't accumulate any shapes with transfer modes.
- if (imageTransferModes && GXGetPictureParts(result, 1, gxSelectToEnd, nil, nil, nil, nil) == 0) {
- GXDisposeShape(result);
- result = nil;
- }//end if
-
- this->PopTransform();
-
- }//end if
-
- return result;
-
- }//CGXtoPostScriptTranslator::InternalDrawShape
-
-
- /**********
- This method pushes a picture transform on the stack.
- **********/
- void CGXtoPostScriptTranslator::PushTransform(gxTransform tr)
- {
- if (mTransformCount + 1 > mStackAllocation) {
-
- /* Allocate a new list and copy old list in */
- gxTransform *newStack = new gxTransform[mStackAllocation + 10]; // grow list by 10 each time.
-
- mStackAllocation += 10;
- if (mTransformCount > 0)
- ::BlockMoveData(mTransformStack, newStack, mTransformCount * sizeof(gxTransform));
-
-
- // Now the stack is the new list.
- delete [] mTransformStack;
- mTransformStack = newStack;
-
- }//end if
-
- /* Now put the new transform on the stack */
- mTransformStack[mTransformCount] = GXCloneTransform(tr); // clone it so that the stack is an ownder.
- mTransformCount += 1;
-
- }//CGXtoPostScriptTranslator::PushTransform
-
- /*************
- This methods pops a picture transform off the stack.
- Note, we never reduce the size of the allocated stack, not worth the trouble.
- **************/
- void CGXtoPostScriptTranslator::PopTransform()
- {
- if (mTransformCount <= 0)
- throw -999;
-
- GXDisposeTransform(mTransformStack[mTransformCount - 1]); // we don't own it anymore.
- mTransformCount -= 1;
-
- }//CGXtoPostScriptTranslator::PopTransform
-
-
-
- /*******************************************************
-
- CGXBuildShapeDbaseTags:
-
- Routine to build font database tags on a shape.
-
- Routine builds font database tags on a shape by
- flattening it. The actual flattened information
- is ignored. We only want to get the tags built.
-
- Routine returns a picture that has the database tags
- on it. This is because flattening does not generate
- the font database on normal shapes, just pictures.
-
- The picture is newly created and must therefore be disposed
- of by the client of this call.
-
- *********************************************************/
- static long dbaseSpoolProc(gxSpoolCommand command, struct gxSpoolBlock *block);
- static long dbaseSpoolProc(gxSpoolCommand command, struct gxSpoolBlock *block)
- {
- #pragma unused (command, block)
- /** do nothing **/
- return(0);
- }
-
- gxShape CGXToPSBuildShapeDbaseTags(gxShape theShape)
- {
- gxSpoolBlock theSpool;
- char dummyBuffer[50]; // a place for graphics to stick data.
- gxShape thePict;
-
- thePict = GXNewShape(gxPictureType);
- GXSetPictureParts(thePict, 0, 0, 1, &theShape, nil, nil, nil);
-
- theSpool.spoolProcedure = NewgxSpoolProc(dbaseSpoolProc);
- theSpool.buffer = dummyBuffer;
- theSpool.bufferSize = 50;
-
- GXFlattenShape(thePict, gxFontListFlatten + gxFontGlyphsFlatten + gxFontVariationsFlatten, &theSpool);
-
- DisposeRoutineDescriptor(theSpool.spoolProcedure);
-
- return(thePict);
-
- }//FHBuildShapeDbaseTags
-
- /*************************************** TRANSFER MODE UITILITIES ***********************************/
-
- Boolean CGXtoPostScriptDoesShapeHaveTMode(gxShape aShape)
- {
- Boolean result = true;
- gxInk theInk = GXGetShapeInk(aShape);
-
- if (TMTestCopyMode(theInk))
- result = false;
- else if (TMTestOrMode(theInk)) { // or mode 1-bit bitmaps can be handled by the imaging engine using the "imagemask" postscript operator.
-
- if (GXGetShapeType(aShape) == gxBitmapType) {
- gxBitmap bits;
- GXGetBitmap(aShape, &bits, nil);
- if (bits.pixelSize == 1)
- result = false;
- }//end if
-
- }//end if
-
- return result;
- }
-
-
-
-
- /************************* DEFAULT IMPLEMENTATION OF THE POSTSCRIPT DEVICE OBJECT *************************/
-
- #include <StdIo.h>
- #include <String.h>
- #include <GXExceptions.h>
-
- /********
- Default status message uses printf.
- *********/
- OSErr CGXtoPostScriptDevice::ReportStatus(long count, unsigned char message[])
- {
- for (int i = 0; i < count; ++i)
- printf("%c", message[i]);
- printf("\n");
- return noErr;
- };
-
- /*******
- This function sends a status message showing
- what font is being downloaded.
- Note: This function could be localized better than this.
- ********/
- OSErr CGXtoPSReportFontDownload(CGXtoPostScriptDevice *dev, gxFont theFont);
- OSErr CGXtoPSReportFontDownload(CGXtoPostScriptDevice *dev, gxFont theFont)
- {
- OSErr status = noErr;
- unsigned char *name;
- long nameLen;
-
- nameLen = GXFindFontName(theFont, gxFullFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, nil, nil);
- if (nameLen > 0) {
- name = new unsigned char[nameLen + 18];
- memcpy(name, "Downloading font: ", 18);
- GXFindFontName(theFont, gxFullFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, name + 18, nil);
- status = dev->ReportStatus(nameLen + 18, name);
- delete [] name;
- }//end if
- return(status);
- }
-
-
-
- /**
- Extended spool block for our font streaming.
- This allows our callback to be handed some extra
- useful data such as:
- **/
- typedef struct {
- gxSpoolBlock gxBlock; // the first field is the gxBlock, so the pointer can be used by GX internally.
- CGXtoPostScriptDevice *psDevice; // A pointer to the device object so we can send messages.
- OSErr status; // A place to store errors
- Boolean canIdle; // This tells us if we can idel during the download process.
- } TGXToPSSpoolBlock;
-
- static long BufferFont( gxSpoolCommand command, gxSpoolBlock *block );
- static long BufferFont( gxSpoolCommand command, gxSpoolBlock *block )
- {
- TGXToPSSpoolBlock *realBlock = (TGXToPSSpoolBlock*)block;
- realBlock->status = noErr;
- if ( command == gxWriteSpool ) {
-
- realBlock->status = realBlock->psDevice->BufferData((char*)(block->buffer), block->count, 0); // send the font data to the printer.
- nrequire(realBlock->status, failed_send);
-
- if (realBlock->canIdle) // give up time if the scaler was reentrent.
- realBlock->status = realBlock->psDevice->Idle();
-
- }//end if
-
- failed_send:
- return(realBlock->status);
-
- }//BufferFont
-
-
- /***************************
- The default implementation of the stream font message.
-
- This method will use GXFlattenFont to pipe font data through
- the BufferData message of the device object.
- ****************************/
- OSErr CGXtoPostScriptDevice::StreamFont(gxFont whatFont, scalerStream *streamRecord)
- {
- OSErr status;
- Boolean streamaction;
- Boolean reentrant;
- TGXToPSSpoolBlock block;
-
- nrequire( status = this->Idle(), JobIdleFailed ); // Idle at least once per call.
-
- /*
- If we are downloding a font, check to see if there is reentrancy in the scaler, and display a status
- message saying what font we are downloading
- */
- if( ( streamaction = ( (streamRecord->action == downloadStreamAction) || (streamRecord->action == asciiDownloadStreamAction) ) ) ) {
- nrequire( status = CGXtoPSReportFontDownload( this, whatFont ), ReportStatusFailed );
- // disable callouts for non-reentrant scalers when downloading.
- reentrant = GXisScalerStreamingReentrant( GXGetFontFormat( whatFont ) ); // see if we can idle during the download.
- }//end if
-
- block.gxBlock.spoolProcedure = NewgxSpoolProc(BufferFont); // Use our buffer proc.
- block.gxBlock.buffer = nil;
- block.gxBlock.bufferSize = 0;
- block.psDevice = this;
- block.canIdle = reentrant;
-
- GXFlattenFont( whatFont, streamRecord, (gxSpoolBlock*)&block );
-
- DisposeRoutineDescriptor(block.gxBlock.spoolProcedure);
-
-
- ReportStatusFailed:
- JobIdleFailed:
- return( status );
-
- }//CGXtoPostScriptDevice::StreamFont
-
-
- /*************
- The default implementation of the printer-glyphs message.
- In the default implmenatation, we'll say that none of the glyphs
- for the font are available.
- **************/
- OSErr CGXtoPostScriptDevice::GetPrinterGlyphsInformation(gxPrinterGlyphsRec *printerGlyphs)
- {
- OSErr status = noErr;
-
- printerGlyphs->platform = gxGlyphPlatform;
- unsigned long *glyphBits = &(printerGlyphs->glyphBits[0]);
- long lwCount = ((printerGlyphs->nGlyphs + 31) / 32);
-
- for (int i = 0; i < lwCount; ++i) // by clearing all of the bits, we signal the font handler to download all glyphs.
- glyphBits[i] = 0;
-
- return(status);
-
- }//CGXtoPostScriptDevice::GetPrinterGlyphsInformation
-
-
- /********
- The default product method
- returns *'s for all 3 names.
- *********/
- OSErr CGXtoPostScriptDevice::GetPSProduct(Str255 version, Str255 revision, Str255 product)
- {
- version[0] = 1;
- version[1] = '*';
-
- revision[0] = 1;
- revision[1] = '*';
-
- product[0] = 1;
- product[1] = '*';
-
- return noErr;
- }
-
-